 #include "point.h"
#include <iostream>
using namespace std;

// 1.方法发没有返回值的时候，关键
void noReturn(int id, string name) {
  cout << "当前学生的Id：" << id << ", 名称为：" << name << endl;
}
// 2. 方法--不需要参数
void mehtodPara(void) { cout << "Exec mehtodPara" << endl; }

void showStudent(int *id, void *name) {
  // 如果使用void* 传递参数
  // void i=10;//不允许
  // 不能用 void 声明变量，它不能代表一个真实的变量。
  //  不能对 void 指针直接解引用 (需要转换成其它类型的指针)。
  cout << "*id:" << *id << ",*name:" << *((string *)name) << endl;
}

int *returnAddree() {
  int i = 10;
  return &i;
}

Point::Point()
{

}

void Point::show(){
    cout << endl << endl;
    cout << "指针==============================================="<< endl;

    //1、获取变量地址
    {
        int a;
        char b;
        bool c;
        string d;

        cout << "十六进制描述地址" << endl;
        cout << "变量a的地址： " << &a << endl;
        cout << "变量b的地址： " << &b << endl;
        cout << "变量c的地址： " << &c << endl;
        cout << "变量d的地址： " << &d << endl;

        cout << "十进制描述地址" << endl;
        cout << "变量a的地址： " << (long long)&a << endl;
        cout << "变量b的地址： " << (long long)&b << endl;
        cout << "变量c的地址： " << (long long)&c << endl;
        cout << "变量d的地址： " << (long long)&d << endl;

        cout << "地址转换成指针输出" << endl;
        cout << "变量a的地址： " << (void*)&a << endl;
        cout << "变量b的地址： " << (void*)&b << endl;
        cout << "变量c的地址： " << (void*)&c << endl;
        cout << "变量d的地址： " << (void*)&d << endl;
    }

    //2、指针--指针变量--占用内存
    //语法：数据类型* 变量名称;
    {
        cout << endl;
        cout << "指针的声明和赋值" << endl;
        int a = 0;
        char b = 'a';
        bool c = true;
        string d = "abc";

        int* pa = &a;
        char* pb = &b;
        bool* pc = &c;
        string* pd = &d;

        cout << "通过指针获取地址" << endl;
        cout << "变量a的地址： " << (long long)pa << ", 指针pa解引用:" << *pa << endl;
        cout << "变量b的地址： " << (long long)pb << ", 指针pb解引用:" << *pb  << endl;
        cout << "变量c的地址： " << (long long)pc << ", 指针pc解引用:" << *pc  << endl;
        cout << "变量d的地址： " << (long long)pd << ", 指针pd解引用:" << *pd  << endl;

        cout << "指针大小" << endl;
        cout << "指针a的大小：" << sizeof(pa) << endl;
        cout << "指针b的大小：" << sizeof(pb) << endl;
        cout << "指针c的大小：" << sizeof(pc) << endl;
        cout << "指针d的大小：" << sizeof(pd) << endl;
    }

    // 如何使用指针：
      {
        int a = 3;
        int* pa = &a;
        cout << "a=" << a << endl;
        cout << "a的值，（对pa解引用）" << *pa << endl;

        a = 20;
        cout << "a=" << a << endl;
        cout << "a的值，（对pa解引用）" << *pa << endl;

        *pa = 40;
        cout << "a=" << a << endl;
        cout << "a的值，（对pa解引用）" << *pa << endl;

        cout << "多个指针可以指向同一个变量==========================" << endl;
        int* pa1 = &a;
        cout << "a=" << a << endl;
        cout << "a的值，（对pa1解引用）" << *pa1 << endl;
      }

    //指针应用在函数的参数
    {
        auto ShowStudent = [](int id, string name){
            cout << "id的大小：" << sizeof(id) << ",id的地址：" << &id << endl;
            cout << "name的大小：" << sizeof(name) << ",name的地址：" << &name << endl;
            cout << "当前学生的id: " << id << ",当前学生的名字： " << name << endl;
        };

        int id = 123;
        string name = "张三";
        ShowStudent(id, name);

        cout << "id的大小：" << sizeof(id) << ",id的地址：" << &id << endl;
        cout << "name的大小：" << sizeof(name) << ",name的地址：" << &name << endl;

    }

    // 通过指针传递参数
    cout << endl;
     cout
         << "节省开销：传递地址；传递地址，就可以使用和操作变量；================]"
         << endl;
     {
       // 1.问题： 什么玩意儿可以保存一个变量的地址？？ 指针
       auto ShowStudentAddreee = [](int* idp, string* namep) {
         *idp = 234;

         cout << "进入到方法了====" << endl;
         cout << "id的大小：" << sizeof(idp) << ", id的地址：" << idp
              << ",id的值：" << idp << endl;
         cout << "name的大小：" << sizeof(namep) << ", name的地址：" << namep
              << ",name的值：" << namep << endl;
         // 得到变量的具体数据：
         cout << "当前学员的id： " << *idp << ",当前学员的名称：" << *namep
              << endl;
       };
       int id = 123;
       string name = "张三";
       cout << "id的大小：" << sizeof(id) << ", id的地址：" << &id << ",id的值："
            << id << endl;
       cout << "name的大小：" << sizeof(name) << ", name的地址：" << &name
            << ",name的值：" << name << endl;
       // int* idp = &id;
       // string* namep = &name;
       // ShowStudentAddreee(idp, namep);
       ShowStudentAddreee(&id, &name);

       cout << "函数执行完毕" << endl;
       cout << "id:" << id << ", name:" << name << endl;
     }

     // 指针用在函数；
       // 定义的函数，如果我需要返回多个值；函数来说，只能返回一个值；
       // 利用执行做函数形参，可以在函数内部修改值；

       {
           // 在方法内部通过解引用，修改指针指向的地址 的值；
           auto returnSecondValue = [](int id, string name, int* idp, string*
           namep) {
             *idp = id+1000;
             *namep = name+"，你好";
           };

           int id = 123;
           string name = "张三";

           int returnidValau = 0;
           string returnnameValue;

           returnSecondValue(id, name, &returnidValau, &returnnameValue);
           cout << "returnidValau：" << returnidValau << endl;
           cout << "returnnameValue：" << returnnameValue << endl;
       }

     // 场景：调用方法,如果我不希望，在方法内部去修改了方法外变量的值呢？
   {
     // 常量指针；
     // 语法： const 数据类型 * 变量名；----声明的指针前面多个了const
     //    const int i = 20;  // 不能修改值；
     //    i = 30;

     {
       int a = 10;
       const int* p = &a;  // 常量指针；
       // 特点：
       int b = 20;
       p = &b;  // 没有问题---修改指针的指向；  1.可以修改指针重新指向另外的变量

       // *p=30; //普通指针可以操作的； 2.常量指针，不允许通过解引用的方式，修改指向的普通变量地址的值；

       auto showStudent = [](const int* ip) {
         // 不希望在方法内部通过街解引用修改 指向的变量的值；
            int b = 30;
            ip = &b; //允许
            cout << "ip的值：" << *ip << endl;
         //    *ip = 30; //不允许
       };

       showStudent(p);

     }
     }

     // 指针常量----引用---换两个名称，被称为引用；
     // 指向的地址：从一而终；
     // 普通指针或者是常量指针：乱指一通；
     // 语法：数据类型* const 变量名称
     {
       // int* px;

       int a = 10;
       int* const p = &a;  // 指针常量--在声明必须要初始化，必须要复制一个变量的地址；

       //      int* const pp;
       // 特点：
       int b = 20;
       // p = &b;  // 1.不允许修改指向；
       *p = 40;  // 2、允许通过解引用的方式，修改指向的普通变量地址的值；
     }

     // 常指针常量，基本没啥用
     //  语法:
     //  const 数据类型 *const 变量名
     {
         // 既然不能更换对于变量地址的指向；
         // 也不能通过解引用修改 变量的值；
     }

     // 总结：
     // 1.常量指针: 指针指向可以改，指针指向的值不可以更改
     // 2.指针常量:指针指向不可以改，指针指向的值可以更改
     // 3.常指针常量:指针指向不可以改，指针指向的值不可以更改。

     {
        // 应该是一个野指针；

        int i = 10;
        auto showinfo = [](int a,int* ip) {

          ip = &a;
//          *ip = a;
          cout << *ip << endl;
        };

        int x = 20;
        showinfo(i, &x);

        cout << x << endl;
    }

     // day7
     //void关键字
     {

     }

     // 栈和堆：
     //  栈和堆的主要区别:
     // 1、管理方式不同:栈是编译器自动管理的，在出作用域时，将自动被释放，堆需手动释放，若程序中不释放，程序结束时由操作系统回收。
     // 2、空间大小不同:堆内存的大小受限于物理内存空间;而栈就小得可怜，一般只有8M(可以修改系统参数)。
     // 3、分配方式不同:堆是动态分配;栈有静态分配和动态分配(都是自动释放)。
     // 4、分配效率不同:栈是系统提供的数据结构，计算机在底层提供了对栈的支持，进栈和出栈有专门的指令，效率比较高;堆是由C++函数库提供的。
     // 5、是否产生碎片:对于栈来说，进栈和出都有着严格的顺序(先进后出)，不会产生碎片，
     // 而堆频繁的分配和释放，会造成内存空间的不连续，容易产生碎片，太多的碎片会导致性能的下降。
     // 6、增长方向不同:栈向下增长，以降序分配内存地址，堆上增长，以升序分配内存地址
     {
        // int *p = new int[100000]; //动态分配内存，保存在堆

        // delete p; //手动回收

        int *p = new int(10);
        cout << "*p: " << *p <<endl;

        *p = 20;
        cout << "*p: " << *p <<endl;
        delete p;
        // 1.动态分配出来的内存没有变量名，只能通过指向它的指针来操作内存中的数据;
        // 2.如果动态分配的内存不用了，必须用delete释放它,否则有可能用尽系统的内存。
     }

     // 二级指针
     {
       // 一级指针--存放普通变量的地址；
       {
         int i = 10;
         int *p = &i;
         int *p1 = new int(20);

         cout << "*p: " << *p <<",*p1: " << *p1 <<endl;
       }

       // 二级指针用于存放指针变量的地址。
       // 声明二级指针的语法:数据类型**指针名
       cout << endl;
       cout << "二级指针==========================" << endl;
       {
           short ii = 8;
           cout << "变量ii的地址：" << &ii << ",变量ii的值：" << ii <<
           endl;

           short *ip = &ii;
           cout << "指针ip的地址" << &ip << ", 指针ip的值：" << ip
                << ",指针ip解引用的值：" << *ip << endl;

           // 二级指针

           short **ipp = &ip;

           cout << "指向ipp的地址：" << &ipp << "，指针ipp的值：" << ipp
                << "，指针ipp解引用：" << *ipp << ",指针ipp解引用两次：" << **ipp
                << endl;
       }
     }

     // 使用指针的目的：
   // 1. 可以传递地址
   // 2. 存放动态分配的内存的地址。
     {
         // 指针传入到方法后，指针会内存拷贝一份指针----指向的地址，是外面定义的指针执行的变量；
         {
           int *p = new int(0);  // 动态分配内存；
           cout << "p=" << p << ",  *p=" << *p << " p的地址：" << &p << endl;

           // 如果希望把动态分配内存，放在一个方法中；
           auto ppsshow = [](int *p) {
             cout << "进入到方法。。。。" << endl;
             cout << "p=" << p << ",  *p=" << *p << " p的地址：" << &p << endl;
             p = new int(200);  // 在函数内部去动态分配内存；
             cout << "p=" << p << ",  *p=" << *p << " p的地址：" << &p << endl;
             //*p = 200;
           };

           ppsshow(p);

           cout << "函数执行完毕后====" << endl;
           cout << "p=" << p << ", *p=" << *p << ",p的地址：" << &p << endl;

           delete p;
         }
         cout << endl;

         cout << "二级指针的应用场景-传递指针的地址=========================="
              << endl;
         // 传递指针的地址

         // 1. 希望在方法内部，动态分配内存，方法内部，必须要通过指针来操作；
         // 2. 方法内部，解引用之后，得到的还必须是个指针；
         // 3. 方法的形参--能够接受一个指针的地址；----二级指针

         // 三级，四级。。。。五六七八~~
         // 问题：
         // 目前，delete 回收内存，回收的是 保存200值的， 之前是保存0的值；
         // 是否能回收呢？
         //
         {
           //          short *sp = new short(1);
           //          short ** sp1= &sp;
           int *p = new int(0);  // 动态分配内存；才能使用堆区；
           cout << "p=" << p << ",  *p=" << *p << " p的地址：" << &p << endl;
           // 如果业务要求，声明指针的代码，分配内存的代码在另外一个函数中；
           auto ppsshow = [](int **p) {
             cout << "进入方法" << &p << endl;
             cout << "p=" << p << ",*p=" << *p << ",**p: " << **p << "，p的地址：" << &p << endl;
             *p = new int(200);
             cout << "给*p再次赋值后:" <<endl;
             cout << "p=" << p << ", *p=" << *p << ",**p: " << **p << ",p的地址：" << &p << endl;
           };

           ppsshow(&p);
           cout << "函数执行完毕后====" << endl;
           cout << "p=" << p << ", *p=" << *p << ",p的地址：" << &p << endl;
           delete p;
         }

     }

     //如果内存被回收了；
     //指针--指向内存的？
     cout << "空指针、野指针==========================" << endl;
     {
         auto func = [](int *p){
             cout << "p=" << p << ", *p=" << *p <<endl;
         };

         int *px = new int(20);
         //int *px;  //只是声明一个指针，没有明确指向某一个内存地址；这是一个空指针；如果传入到方法中，解引用，会导致程序崩溃；
         func(px);

         // int *px1 = nullptr; // 这是一个空指针；如果传入到方法中，解引用，会导致程序崩溃；
         // func(px1);

         delete px;
     }
     // 野指针
     {
       // int *p = (int *)0x00000000000;  // 给的是一个无效的内存地址；
       //  指针指向的地址；会释放了； 指针不会置空；但是地址已经生效了；
       //  1)指针在定义的时候，如果没地方指，就初始化为 nullptr。
       //  2)动态分配的内存被释放后，将其置为 nullptr。
       //  3)函数不要返回局部变量的地址。
       //  注意:野指针的危害比空指针要大很多，在程序中，如果访问野指针，可能会造成程序的崩溃。
       // int* i=  returnAddree();
     }

   cout << endl;
   cout << "一维数组和指针--------------------" << endl;
   // 指针的算术
   // 普通指针变量的算术（非数组指针变量）：
   // 普通变量---地址+1；  地址+ 对应的类型的字节数量的单位长；
   {
     char a;
     short b;
     int c;
     double d;
     cout << "sizeof(a)=" << sizeof(a) << endl;
     cout << "sizeof(b)=" << sizeof(b) << endl;
     cout << "sizeof(c)=" << sizeof(c) << endl;
     cout << "sizeof(d)=" << sizeof(d) << endl;

     cout << endl;
     cout << "地址=========================" << endl;
     cout << "a的地址：" << (long long)&a << endl;
     cout << "a的地址+1：" << (long long)(&a + 1) << endl;
     cout << "b的地址：" << (long long)&b << endl;
     cout << "b的地址+1：" << (long long)(&b + 1) << endl;
     cout << "c的地址：" << (long long)&c << endl;
     cout << "c的地址+1：" << (long long)(&c + 1) << endl;
     cout << "d的地址：" << (long long)&d << endl;
     cout << "d的地址+1：" << (long long)(&d + 1) << endl;
     // C++内存是连续存储的；
     //  输出的地址：默认是16进制的数字，转成十进制；
     //  还是数字，既然是数字，一定可以做计算；
     // 地址的计算----什么东西可以保存变量的地址:  指针；
   }

   // // 1)指针的算术
   // 数组：连续存储的相同长度的内存单元；
   //   数组指针变量的算术：
   cout << endl;
   cout << "数组指针变量的算术" << endl;
   {
      {
       short a[5];
       cout << "a的值" << a <<endl;
       cout << "a的地址" << &a << endl;
       cout << "a[0]的地址：" << &(a[0]) << endl;
       cout << "a[1]的地址：" << &(a[1]) << endl;
       cout << "a[2]的地址：" << &(a[2]) << endl;
       cout << "a[3]的地址：" << &(a[3]) << endl;
       cout << "a[4]的地址：" << &(a[4]) << endl;

       short *p = a;  // 指针指向了这个数组的地址；

       cout << "p的值：" << p << endl;
       cout << "p+0的地址：" << p + 0 << endl;
       cout << "p+1的地址：" << p + 1 << endl;
       cout << "p+2的地址：" << p + 2 << endl;
       cout << "p+3的地址：" << p + 3 << endl;
       cout << "p+4的地址：" << p + 4 << endl;

       // 小节：
       // 1.数据可以通过数组描述法 获取值
       // 2.指针指向数组地址后，也可以通过指针运算得到每一个元素的地址；
      }

       // 既然可以通过指针计算得到数组元素的地址；
       // 自然就可以通过指针计算后，解引用得到数组的元素值；
     {
       short a[5] = {20, 50, 60, 22, 15};
       cout << "a[0]的值是：" << a[0] << endl;
       cout << "a[1]的值是：" << a[1] << endl;
       cout << "a[2]的值是：" << a[2] << endl;
       cout << "a[3]的值是：" << a[3] << endl;
       cout << "a[4]的值是：" << a[4] << endl;
       cout << endl;
       short *p = a;
       cout << "p+0的值是：" << (long long)p << endl;
       cout << "p+1的值是：" << (long long)(p + 1) << endl;
       cout << "p+2的值是：" << (long long)(p + 2) << endl;
       cout << "p+3的值是：" << (long long)(p + 3) << endl;
       cout << "p+4的值是：" << (long long)(p + 4) << endl;
       cout << endl;
       cout << "*(p+0)的值是：" << *(p) << endl;
       cout << "*(p+1)的值是：" << *(p + 1) << endl;
       cout << "*(p+2)的值是：" << *(p + 2) << endl;
       cout << "*(p+3)的值是：" << *(p + 3) << endl;
       cout << "*(p+4)的值是：" << *(p + 4) << endl;

       // 小节：
       // 2==数组的地址
       // a)、数组在内存中占用的空间是连续的。
       // b)、C++将数组名解释为数组第0个元素的地址。
       // c)、数组第0个元素的地址和数组首地址的取值是相同的。
       // d)、数组第n个元素的地址是：数组首地址+n ;
       // e)、C++编译器把 数组名[下标]  解释为  *(数组首地址+下标)
     }

       // 数组的本质--是什么？  其实就是一个指针；
       // 数组是占用连续空间的一块内存，数组名解释为数组第0个元素的地址。
       // C++操作这块内存有两种方法:数组解释法和指针表示法，它们是等价的。
       // 注意：4)数组名不一定会被解释为地址，在多数情况下，C++将数组名解释为数组的第0个元素的地址，但是，将
       // sizeof运算符用于数据名将返回整个数组占用内存空间的字节数。
       // 可以修改指针的值，但数组名是常量，不可修改。
       //
   }

   // 注意：
   // 4)重点注意：
   //******数组名不一定会被解释为地址，在多数情况下，C++将数组名解释为数组的第0个元素的地址，
   // 但是，将sizeof运算符用于数据名将返回整个数组占用内存空间的字节数。如果把数组传入到方法，
   // 写的是数组名，其实是传入的数组地址；

   {
     int xp[5];
     cout << "sizeof(xp)=" << sizeof(xp) << endl;
   }



}
